package liquidfs.data.ops;

import java.util.*;

import liquidfs.*;
import liquidfs.core.*;
import liquidfs.data.*;
import liquidfs.data.fs.*;

public abstract class AbstractFileModificationOperation extends AbstractOperation<Void> implements FileOperation<Void>, ModificationOperation<Void> {
   
   private List<Revision> revisions;
   private String filepath;
   private Date modificationDate;
   
   public AbstractFileModificationOperation(Revision current, Revision previous, String filepath) {
      super(current.getDevice());
      
      this.filepath = filepath;
      this.modificationDate = new Date();
      
      this.revisions = new ArrayList<Revision>(2);
      this.revisions.add(current);
      this.revisions.add(previous);
   }
   
   @Override
   public Date getModificationDate () {
      return this.modificationDate;
   }
   
   @Override
   public Revision getCurrentRevision () {
      return revisions.get(0);
   }
   
   @Override
   public Revision getPreviousRevision () {
      return revisions.get(1);
   }
   
   @Override
   public List<Revision> getRevisions () {
      return revisions;
   }
   
   @Override
   public boolean isModification () {
      return true;
   }
   
   @Override
   public boolean isFileOperation () { 
      return true;
   }
   
   @Override
   public boolean isIgnored (Application app) {
      
      // Get the filesystem
      LiquidFileSystem fs = app.getFileSystem();
      
      // We can only make a judgement about it if we have a local copy of the file
      if (fs.isLocal(this.getFilePath())) {
         
         Revision current = fs.getMetadata(this.getFilePath()).getRevision();
         
         // If the revision number is greater than the one we have...
         if (this.getCurrentRevision().getRevisionNumber() > current.getRevisionNumber())
         {
            // See if we can find the revision that we have in the list of past revisions
            for (int i = 1; i < this.getRevisions().size(); ++i) {
               
               // If one of them equals our current revision, then we can accept this modification operation
               Revision revision = this.getRevisions().get(i);
               if (revision.equals(current)) {
                  return false;
               }
            }
         }
         
         // Otherwise, we ignore it
         return true;
      }
      
      // We can't ignore things that aren't local, we must pass them on
      return false;
   }
   
   @Override
   public boolean isConflicting (Application app) {
      
      // Get the filesystem
      LiquidFileSystem fs = app.getFileSystem();
      
      // We can only make a judgement about it if we have a local copy of the file
      if (fs.isLocal(this.getFilePath())) {
         
         Revision current = fs.getMetadata(this.getFilePath()).getRevision();
         
         // If the received revision has the same revision number as we do, but a DIFFERENT device, then it is in conflict
         if (this.getCurrentRevision().getRevisionNumber() == current.getRevisionNumber() && !this.getCurrentRevision().getDevice().equals(current.getDevice()))
            return true;
         
         // See if we can find the revision number that we have in the list of past revisions
         for (int i = 1; i < this.getRevisions().size(); ++i) {
            
            // If one of them equals our current revision number, but has a different device, then this is also a conflict
            Revision revision = this.getRevisions().get(i);
            if (revision.getRevisionNumber() == current.getRevisionNumber() && !revision.getDevice().equals(current.getDevice())) {
               return true;
            }
         }
      }
      
      // It is not a direct conflict
      return false;
   }
   
   @Override
   public String getFilePath () {
      return this.filepath;
   }
}
